#ifndef _TYPES_H_
#define _TYPES_H_

#define MAX_NAME_LEN    128     
typedef int          boolean;
typedef uint16_t     flag16;

typedef enum newfs_file_type{
    NEWFS_REG_FILE,
    NEWFS_DIR,
    NEWFS_SYM_LINK
}NEWFS_FILE_TYPE;

#define TRUE                    1
#define FALSE                   0
#define UINT32_BITS             32
#define UINT8_BITS              8

#define NEWFS_MAGIC_NUM         0x52415453
#define NEWFS_SUPER_OFS         0
#define NEWFS_ROOT_INO          0



#define NEWFS_ERROR_NONE          0
#define NEWFS_ERROR_ACCESS        EACCES
#define NEWFS_ERROR_SEEK          ESPIPE     
#define NEWFS_ERROR_ISDIR         EISDIR
#define NEWFS_ERROR_NOSPACE       ENOSPC
#define NEWFS_ERROR_EXISTS        EEXIST
#define NEWFS_ERROR_NOTFOUND      ENOENT
#define NEWFS_ERROR_UNSUPPORTED   ENXIO
#define NEWFS_ERROR_IO            EIO     /* Error Input/Output */
#define NEWFS_ERROR_INVAL         EINVAL  /* Invalid Args */

#define NEWFS_MAX_FILE_NAME       128
#define NEWFS_INODE_PER_FILE      1
#define NEWFS_DATA_PER_FILE       7
#define NEWFS_DEFAULT_PERM        0777

#define NEWFS_IOC_MAGIC           'S'
#define NEWFS_IOC_SEEK            _IO(NEWFS_IOC_MAGIC, 0)

#define NEWFS_FLAG_BUF_DIRTY      0x1
#define NEWFS_FLAG_BUF_OCCUPY     0x2
/******************************************************************************
* SECTION: Macro Function
*******************************************************************************/
#define NEWFS_IO_SZ()                     (nfs_super.sz_io)
#define NEWFS_BLK_SZ()                    (nfs_super.sz_blks)
#define NEWFS_DISK_SZ()                   (nfs_super.sz_disk)
#define NEWFS_DRIVER()                    (nfs_super.fd)
#define NEWFS_BLKS_SZ(blks)               ((blks) * NEWFS_BLK_SZ())
#define NEWFS_DENTRY_PER_BLK()          (NEWFS_BLK_SZ() / sizeof(struct newfs_dentry))

#define NEWFS_ROUND_DOWN(value, round)    ((value) % (round) == 0 ? (value) : ((value) / (round)) * (round))
#define NEWFS_ROUND_UP(value, round)      ((value) % (round) == 0 ? (value) : ((value) / (round) + 1) * (round))

#define NEWFS_ASSIGN_FNAME(pnfs_dentry, _fname)\
                                        memcpy(pnfs_dentry->fname, _fname, strlen(_fname))

#define NEWFS_INO_OFS(ino)                (nfs_super.inode_offset + NEWFS_BLKS_SZ(ino))
#define NEWFS_DATA_OFS(dno)               (nfs_super.data_offset + NEWFS_BLKS_SZ(dno))

#define NEWFS_IS_DIR(pinode)              (pinode->dentry->ftype == NEWFS_DIR)
#define NEWFS_IS_REG(pinode)              (pinode->dentry->ftype == NEWFS_REG_FILE)
#define NEWFS_IS_SYM_LINK(pinode)         (pinode->dentry->ftype == NEWFS_SYM_LINK)

struct custom_options {
	const char*        device;
    boolean            show_help;
};

struct newfs_inode {
    int                  ino;
    int                  size;
    int                  link;
    NEWFS_FILE_TYPE      ftype;
    int                  block_pointer[NEWFS_DATA_PER_FILE];
    int                  dir_cnt;
    struct newfs_dentry* dentry;
    struct newfs_dentry* dentrys;
    uint8_t*             data[NEWFS_DATA_PER_FILE];
    int                  block_allocted;
    boolean              dirty[NEWFS_DATA_PER_FILE];
    /* TODO: Define yourself */
};

struct newfs_dentry {
    char     fname[MAX_NAME_LEN];
    uint32_t ino;
    struct newfs_dentry* parent;
    struct newfs_dentry* brother;
    struct newfs_inode*  inode;
    NEWFS_FILE_TYPE      ftype;
    /* TODO: Define yourself */
};

struct newfs_super {
    uint32_t magic;
    int                 fd;

    int                 sz_io;
    int                 sz_blks;//块大小是两倍IO块
    int                 sz_disk;
    int                 sz_usage;

    int                 max_ino;
    uint8_t*            map_inode;
    int                 map_inode_blks;
    int                 map_inode_offset;
    int                 inode_offset;


    int                 max_dno;
    int                 max_data;        // 数据块最大数目
    uint8_t*            map_data;        // data位图
    int                 map_data_offset; // data位图的起始地址
    int                 map_data_blks;   // data位图所占的块数
    int                 data_offset;
    
    boolean             is_mounted;
    
    struct newfs_dentry*  root_dentry;
    /* TODO: Define yourself */
};

static inline struct newfs_dentry* new_dentry(char * fname, NEWFS_FILE_TYPE ftype){
    struct newfs_dentry * dentry = (struct newfs_dentry *) malloc(sizeof(struct newfs_dentry));
    memset(dentry, 0, sizeof(struct newfs_dentry));
    NEWFS_ASSIGN_FNAME(dentry, fname);
    dentry->ftype   = ftype;
    dentry->ino     = -1;
    dentry->inode   = NULL;
    dentry->parent  = NULL;
    dentry->brother = NULL;
    return dentry;       
}
/******************************************************************************
* SECTION: FS Specific Structure - Disk structure
*******************************************************************************/

struct newfs_super_d
{
    uint32_t            magic_num;
    uint32_t            sz_usage;

    int                map_inode_blks;
    int                map_inode_offset;

    int                map_data_offset;
    int                map_data_blks;

    int                data_offset;
    int                inode_offset;
};

struct newfs_inode_d
{
    uint32_t            ino;
    uint32_t            size;
    int                 link;
    int                 block_pointer[NEWFS_DATA_PER_FILE];// 数据块指针（可固定分配）
    uint32_t            dir_cnt;
    NEWFS_FILE_TYPE     ftype;
};

struct newfs_dentry_d
{
    char                fname[NEWFS_MAX_FILE_NAME];
    NEWFS_FILE_TYPE     ftype;
    uint32_t            ino;
};

#endif